package com.fJdbcUtil.util;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.logging.Logger;
import javax.sql.DataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
/**
 * 自定义jdbc的工具类，可以方便快捷的完成增删该查的操作
 * FullJDBC  简称 fjdbc
 * @title   FJdbc.java
 * @author  付军
 * @data    2020年6月4日下午3:36:38
 * @version 1.0
 */
public class FJdbc {

	private static  Logger   logger=Logger.getLogger("FJdbc");
	//private static HikariConfig   hc=new HikariConfig("/jdbc.properties");
	//private static  HikariDataSource ds=new HikariDataSource(hc);
	private static  Properties   properties=new Properties();
	private static  DataSource   ds;
	static {
		try {
			/*
			 *要求配置文件的名字是 jdbc.properties   放置路径位 src的目录下即可
			 */
			properties.load(FJdbc.class.getClassLoader().getResourceAsStream("jdbc.properties"));
			ds=new DruidDataSourceFactory().createDataSource(properties);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}




	private static Connection conn;
	private static PreparedStatement  pstmt;
	private static ResultSet rs;


	/**
	 * 获取连接的方法
	 * @return 返回一个标准的Connection连接对象
	 */
	public static  Connection  getConnection() {
		try {
			return ds.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 关闭资源的方法
	 * @param conn   连接对象
	 * @param pstmt  sql语句执行对象
	 * @param rs     结果集对象
	 */
	public static  void close(Connection conn,Statement pstmt,ResultSet rs) {
		try {
			if(conn!=null) {
				conn.close();
			}
			if(pstmt!=null) {
				pstmt.close();
			}
			if(rs!=null) {
				rs.close();
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 无参数的查询方法
	 * @param sql
	 * @param cl
	 * @return
	 */
	public  static <T>List<T> queryList(String sql,Class<T> cl){
		return queryList(sql, cl,null);
	}
	/**
	 * 查询的方法         要求用户查询的类的属性名字和  数据库表中的字段名字保持一致
	 * @param sql    查询语句
	 * @param cl     list集合中保存的对象类型
	 * @param params 参数数组
	 * @return       list集合结果集
	 */
	public  static <T>List<T> queryList(String sql,Class<T> cl,Object[] params){
		List<T>  list=new ArrayList<T>();
		try {
			conn=ds.getConnection();
			pstmt=conn.prepareStatement(sql);
			if(params!=null) {
				for (int i = 0; i < params.length; i++) {
					pstmt.setObject(i+1, params[i]);
				}
			}
			executeResoutSet( cl, list);
		} catch (SQLException e) {

			e.printStackTrace();
		}  catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			close(conn, pstmt, rs);;
		}
		return list;
	}


	/**
	 * 增删改的方法
	 * @param sql
	 * @param objs
	 * @return  受影响的数量
	 */
	public static  int  update(String sql,Object[] objs) {

		try {
			conn=ds.getConnection();
			pstmt=conn.prepareStatement(sql);
			if(objs!=null) {
				for (int i = 0; i < objs.length; i++) {
					pstmt.setObject(i+1, objs[i]);
				}
			}
			return pstmt.executeUpdate();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			close(conn, pstmt, rs);;
		}
		return 0;
	}



	/**
	 * 从数据库中查询单条记录-如果传入的而是HashMap集合，则返回一个Map对象
	 * @param sql
	 * @param objclass
	 * @param params
	 * @return 查询的结果对象 ，对象类型由objecclass指定
	 */
	public  static <T>T queryOne(String sql,Class<T> objclass,Object[] params){
		try {
			conn=ds.getConnection();
			pstmt=conn.prepareStatement(sql);
			if(params!=null) {
				for (int i = 0; i < params.length; i++) {
					pstmt.setObject(i+1, params[i]);
				}
			}
			rs=pstmt.executeQuery();
			ResultSetMetaData  rsmd=  rs.getMetaData();
			//属性的名字和 查询的列明保持一致
			if(rs.next()) {
				return (T)queryObj(objclass,rs,rsmd);
			}
		} catch (SQLException e) {

			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			System.out.println("aa");
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			logger.severe("请注意你查询的数据库字段的名字是否和你实体类中的名字保持一致,否则有一个字段没有数据");
			e.printStackTrace();
		}finally {
			close(conn, pstmt, rs);;
		}
		return null;
	}


	/**
	 * 从数据库中查询单条记录-如果传入的而是HashMap集合，则返回一个Map对象
	 * @param sql
	 * @param objclass
	 * @return  单个结果对象
	 */
	public  static <T>T queryOne(String sql,Class<T> objclass){
		return queryOne(sql, objclass, null);
	}




	/**
	 * 处理map集合的方法
	 * @param obj
	 * @param rsmd
	 * @param rs
	 */
	private static  void MapObj(Object obj,ResultSetMetaData  rsmd,ResultSet rs) {
		try {
			for (int i = 1; i <=rsmd.getColumnCount(); i++) {
				//获取到列的名字
				String columnName=rsmd.getColumnLabel(i);
				Method  method=  obj.getClass().getMethod("put",Object.class,Object.class);
				method.invoke(obj,columnName,rs.getObject(i));
			}
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}


	/**
	 * 处理结果集的方法
	 */
	 private static <T> void   executeResoutSet(Class<T> cl,List<T> list){
		 try {
			 rs=pstmt.executeQuery();
			 ResultSetMetaData  rsmd=  rs.getMetaData();
			 //属性的名字和 查询的列明保持一致
			 while(rs.next()) {
				 //通过反射机制获取一个对象
				 list.add((T)queryObj(cl,rs,rsmd));
			 }

		 } catch (SQLException e) {
			 e.printStackTrace();
		 } catch (IllegalAccessException e) {
			 e.printStackTrace();
		 } catch (InstantiationException e) {
			 e.printStackTrace();
		 } catch (NoSuchFieldException e) {
			 e.printStackTrace();
		 }
	 }

	 private static <T>Object queryObj(Class<T> cl,ResultSet rs,ResultSetMetaData rsmd) throws IllegalAccessException, InstantiationException, SQLException, NoSuchFieldException {
		 Object obj=cl.newInstance();
		 if(obj instanceof Map) {
			 MapObj(obj,rsmd,rs);
		 }else {
			 for (int i = 1; i <=rsmd.getColumnCount(); i++) {
				 //将列的名字获取到--是别名
				 String columnName=rsmd.getColumnLabel(i);
				 //根据列的名字获取到属性对象
				 Field f=cl.getDeclaredField(columnName);
				 f.setAccessible(true);
				 Object fieldVlaue=rs.getObject(i);
				 try {
					 if(fieldVlaue instanceof LocalDateTime){
						 Instant instant=((LocalDateTime)fieldVlaue).atZone(ZoneId.systemDefault()).toInstant();
						 f.set(obj,Date.from(instant));
					 }else{
						 f.set(obj, fieldVlaue);
					 }
				 }catch(IllegalArgumentException ie) {
					 logger.severe("请注意你查询的数据库字段的类型也必须要和实体类中的属性类型保持一致,否则有一个字段没有数据");
					 logger.severe(ie.getMessage());
				 }
			 }
		 }
		 return (T)obj;
	 }
}
